# 建立一个空的对象
from cacheout import Cache

empty = object()


# 一个装饰器，对__getattr__进行装饰，使得其可以进行类的实例化
def proxy_getattr(func):
    def wrapper(self, *args):
        if self._wrapper is empty:
            self._init_object()
        return func(self._wrapper, *args)

    return wrapper


class LazyObject(object):

    def __init__(self):
        self._wrapper = empty

    __getattr__ = proxy_getattr(getattr)

    # 进行赋值操作的时候，看是实例化类，还是对类的实例进行赋值操作。因为下面我们要进行实例化类的操作。
    def __setattr__(self, key, value):
        if key == '_wrapper':
            self.__dict__['_wrapper'] = value
        else:
            if self._wrapper is empty:
                self._init_object()
            setattr(self._wrapper, key, value)

    # 在子类中，你应该重新定义它，你通过它，来实现你想要通过何种方式实例化你的类。
    def _init_object(self):
        pass


class CommonLazyObject(LazyObject):

    def __init__(self, func):
        self.__dict__['_wrapperfunc'] = func
        super(CommonLazyObject, self).__init__()

    def _init_object(self):
        self._wrapper = self._wrapperfunc()


class User(object):

    def __init__(self,p):
        print('haib')
        print(p)
        self.name = 'haibo'
        self.age = 23

    def get_data(self):
        print('data')

class Zser(object):

    def __init__(self):
        print('Zser')

    def get_s(self):
        print('dataZser')


def test():
    return User()

class lazyfunc(object):
    def __init__(self, func):
        self.func = func

    def __get__(self, instance, cls):
        val = self.func(instance)
        setattr(instance, self.func.__name__, val)
        return val

class Circle(object):

    cache = Cache()
    def __init__(self, radius):
        print('init')
        self.radius = radius

    @lazyfunc
    def area(self):
        print('evalute')
        return 3.14 * self.radius ** 2

c = Circle(4)
print (c.radius)
print (c.area)
print (c.area)
print (c.area)


# 初始化该延迟加载类

user = CommonLazyObject(lambda: User('aa'))
z = CommonLazyObject(Zser)
print('go')
# 此时我们要引用的类才执行
user.get_data()
user.a = 'tt'
print(user.a)
z.get_s()
print(z.a)
